// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: linchuan

#pragma once

#include <cstdio>
#include <map>
#include <memory>
#include <set>
#include <string>

#include <rapidjson/document.h>

#include "coin2/exchange/base/order/order.h"
#include "coin2/exchange/binance/symbology/product.h"
#include "coin2/exchange/binance_base/api_util/rate_tracker.h"

namespace coin2::exchange::binance::order_v1 {

class BinanceParser : public base::order::BaseParser {
 public:
  using TransferType = coin::proto::TransferRequestProto::TransferType;

 public:
  const ParseResult& ParseRawMessage(const RawMessage& msg) override;
  AccountBalance ParseBalance(const JsonValue& document) override;
  bool ParseRawMarginCrossedBalance(const JsonValue& doc, RawBalanceMap* raw_balance_map);
  bool ParseRawMarginIsolatedBalance(const JsonValue& doc, RawBalanceMap* raw_balance_map);
  bool ParseRawMarginIsolatedAssets(const JsonValue& doc, RawBalanceMap* raw_balance_map);

 private:
  void ParseSubmitResponse();
  void ParseCancelResponse();
  void ParseRestOpenOrders();
  void ParseRestAllOrders();
  void ParseRestOrderInfoList();
  void ParseRestFillInfoList();
  void ParseRestSpotAccountBalance();
  void ParseRestEarnFlexibleProductPosition();
  void ParseRestEarnLockedProductPosition();
  AccountBalance GetAccountBalance();
  void MergeEarnPosition(const std::string& native_currency, CurrencyBalance* balance);
  void ParseRestMarginCrossedAccountBalance();
  void ParseRestMarginIsolatedAccountBalance();
  void ParseWsMessage();
  void ParseListenKey();
  void ParseRestDeposit();
  void ParseRestWithdrawal();
  void ParseTransfer(bool is_deposit_subaccount);
  ProductOrderBundle ParseWsOrderInfoListV2(const JsonValue& data);
  ProductFillBundle ParseWsFillInfoListV2(const JsonValue& data);
  std::string ParseHeader(const std::shared_ptr<AsioHttpContext>&);
  bool ParseWsBalance(const JsonValue& doc, AccountBalance*);
  ProductOrderElement ParseRestOrderInfo(const JsonValue&);
  bool ParseRawBalanceFromWs(const JsonValue& doc, RawBalanceMap* raw_balance_map);
  void MergeMarginAccountBalance(AccountBalance* acc_balance);
  bool IsValidBinanceResponse(const std::shared_ptr<AsioHttpContext>& http_context);
  void CheckAndForceResetWssConnection();

 private:
  bool is_query_historical_orders_{false};
  int64_t last_ws_balance_timestamp_{0};
  bool is_account_balance_initialized_ = false;
  bool is_flexible_product_position_initialized_ = false;
  bool is_locked_product_position_initialized_ = false;
  RawBalanceMap account_balance_map_cache_;
  RawBalanceMap flexible_product_position_map_cache_;
  RawBalanceMap locked_product_position_map_cache_;
  static std::map<std::string, TransferType> transfer_type_map_;
  bool is_crossed_margin_balance_initialized = false;
  bool is_isolated_margin_balance_initialized = false;
  RawBalanceMap crossed_margin_balance_map_cache_;
  RawBalanceMap isolated_margin_balance_map_cache_;
  std::map<std::string, std::string> transfer_deposit_map_;
  bool is_transfer_deposit_initialized_ = false;
  std::map<std::string, std::string> transfer_withdrawal_map_;
  bool is_transfer_withdrawal_initialized_ = false;
  std::map<std::string, std::string> transfer_account_map_;
  bool is_transfer_deposit_subaccount_initialized_ = false;
  bool is_transfer_withdrawal_subaccount_initialized_ = false;

  // for wss health checking
  int64_t rest_transaction_update_et_ = 0;
  int64_t wss_transaction_update_et_ = 0;
};

}  // namespace coin2::exchange::binance::order_v1
